package com.syh.jn.scm.service.impl.supplier.statistics;

import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import cn.redscarf.commons.wrapper.expression.orderExpression.Order;
import com.alibaba.dubbo.config.annotation.Service;
import com.syh.jn.scm.domain.supplier.entity.stock.StockGoods;
import com.syh.jn.scm.domain.supplier.repository.finance.archive.ArchiveReadRepository;
import com.syh.jn.scm.domain.supplier.repository.stock.StockGoodsReadRepository;
import com.syh.jn.scm.dto.supplier.finance.archive.ArchiveStockVo;
import com.syh.jn.scm.dto.supplier.finance.archive.ArchiveVo;
import com.syh.jn.scm.dto.supplier.statistics.stock.InventoryReportVo;
import com.syh.jn.scm.infrastructure.repository.utils.MybatisTemplate;
import com.syh.jn.scm.service.api.supplier.statistics.StockInventoryReportService;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class StockInventoryReportServiceImpl implements StockInventoryReportService {

  @Resource(name="archiveRepoMbImpl")
  private ArchiveReadRepository archiveReadRepository;

  @Override
  public List<InventoryReportVo> inventoryReport(Map<String, Object> params) {
//    return MybatisTemplate.selectList("stockInventoryQRepository.inventoryReport",params);
    return getInventoryReport(params);
  }

  @Override
  public Integer inventoryReportCount(Map<String, Object> params) {
//    return MybatisTemplate.selectOne("stockInventoryQRepository.inventoryReportCount",params);
    StockGoodsReadRepository stockGoodsReadRepository = (StockGoodsReadRepository) SpringContextUtils.getBean("stockGoodsRepositoryImpl");
    Wrapper wrapper = Wrapper.build();
    this.setQuery(wrapper,params);
    return stockGoodsReadRepository.getCount(wrapper);
  }

  public List<InventoryReportVo> getInventoryReport(Map<String, Object> params) {
    StockGoodsReadRepository stockGoodsReadRepository = (StockGoodsReadRepository) SpringContextUtils.getBean("stockGoodsRepositoryImpl");
    //获取要分页统计的库存商品列表
    Integer startRow = (Integer) params.get("startRow");
    Integer pageSize = (Integer) params.get("pageSize");
    Long businessEntityId = (Long) params.get("businessEntityId");
    Wrapper stockWp = Wrapper.build();
    this.setQuery(stockWp,params);
    List<StockGoods> stockGoodsList = stockGoodsReadRepository.findListPage(stockWp,startRow,pageSize);
    //报表统计开始时间 如果没有选择开始时间  默认是从最初开始查询
    String reportBeginTimeStamp = params.get("beginTime") == null ? "0" : (String)params.get("beginTime");
    //如果没有选择结束时间  默认到当前时间
    String reportEndTimeStamp = params.get("endTime") == null ? String.valueOf(System.currentTimeMillis()) : (String)params.get("endTime");

//    Map<String,InventoryReportVo> inventoryReportVoMap = this.getBeginStock(reportBeginTimeStamp,businessEntityId);
//    this.setMiddleStock(reportBeginTimeStamp,reportEndTimeStamp,inventoryReportVoMap,businessEntityId);
//    this.setEndStock(reportEndTimeStamp,businessEntityId,inventoryReportVoMap);
    Map<String,InventoryReportVo> inventoryReportVoMap = StockInventoryUtils.getStockInventory(reportBeginTimeStamp,reportEndTimeStamp,businessEntityId);
    List<InventoryReportVo> reportVos = new ArrayList<>();
    stockGoodsList.forEach(stockGoods -> {
      String key = stockGoods.getStorehouseId()+":"+stockGoods.getGoodsId();
      if (inventoryReportVoMap.get(key) != null) {
        reportVos.add(inventoryReportVoMap.get(key));
      }
    });

    return reportVos;
  }

  private void setQuery(Wrapper wrapper,Map<String,Object> params) {
    wrapper.append(Restrictions.eq("businessEntityId",(Long)params.get("businessEntityId")));
    if (params.get("storehouseId") != null) {
      wrapper.append(Restrictions.eq("storehouseId",(String)params.get("storehouseId")));
    }
    if (params.get("goodsName") != null) {
      wrapper.append(Restrictions.like("name",(String)params.get("goodsName")));
    }
  }

  /**
   * 获取统计报表的期初数据(期初库存)
   * @param beginTimeStamp
   * @return
   */
  private Map<String,InventoryReportVo> getBeginStock(String beginTimeStamp,Long businessEntityId) {
    Map<String,InventoryReportVo> inventoryReportVoMap = new HashMap<>();
    List<InventoryReportVo> inventoryReportVos = null;
    Map<String,Object> param = new HashMap<>();
    Wrapper wrapper = Wrapper.build().append(Restrictions.eq("businessEntityId",businessEntityId)).append(Restrictions.lt("archiveEndTimeStamp",beginTimeStamp)).order(Order.desc("archiveEndTimeStamp"));
    ArchiveVo archiveVo = archiveReadRepository.getOne(wrapper);
    if (archiveVo != null) {
      List<ArchiveStockVo> archiveStockVos = (List<ArchiveStockVo>) archiveReadRepository.findStockByArchiveId(archiveVo.getId());
      param.put("beginTime",archiveVo.getArchiveEndTimeStamp());
      param.put("endTime",beginTimeStamp);
      param.put("businessEntityId",businessEntityId);
      inventoryReportVos = MybatisTemplate.selectList("stockInventoryQRepository.getStockRecordByTimeFrame",param);
      inventoryReportVos.forEach(inventoryReportVo -> {
        inventoryReportVo.setBeginningQuantity(inventoryReportVo.getRecordQuantity());
        inventoryReportVo.setBeginningBalance(inventoryReportVo.getRecordBalance());
        //平均成本为库存总额除以库存数量
        BigDecimal avgCost = inventoryReportVo.getRecordQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : inventoryReportVo.getRecordBalance().divide(inventoryReportVo.getRecordQuantity(),5);

        //其余字段清零
        inventoryReportVo.setRecordQuantity(BigDecimal.ZERO);
        inventoryReportVo.setRecordBalance(BigDecimal.ZERO);
        inventoryReportVo.setRecordAvgCost(BigDecimal.ZERO);
        inventoryReportVo.setBeginningAvgCost(avgCost);
        inventoryReportVo.setSaleQuantity(BigDecimal.ZERO);
        inventoryReportVo.setSaleRetQuantity(BigDecimal.ZERO);
        inventoryReportVo.setPurQuantity(BigDecimal.ZERO);
        inventoryReportVo.setPurRetQuantity(BigDecimal.ZERO);
        inventoryReportVo.setOtherInQuantity(BigDecimal.ZERO);
        inventoryReportVo.setOtherOutQuantity(BigDecimal.ZERO);
        inventoryReportVo.setLossQuantity(BigDecimal.ZERO);
        inventoryReportVo.setSpillQuantity(BigDecimal.ZERO);
        inventoryReportVoMap.put(inventoryReportVo.getDepotId()+":"+inventoryReportVo.getGoodsId(),inventoryReportVo);
      });
      archiveStockVos.forEach(archiveStockVo -> {
        String key = archiveStockVo.getDepotId()+":"+archiveStockVo.getGoodsId();
        if (inventoryReportVoMap.get(key) != null) {
          InventoryReportVo inventoryReportVo = inventoryReportVoMap.get(key);
          //库存数量为期初库存加时间段内库存
          BigDecimal quantity = archiveStockVo.getTotalQuantity().add(inventoryReportVo.getBeginningQuantity());
          inventoryReportVo.setBeginningQuantity(quantity);
          //库存总额为期初总额加时间段内总额
          BigDecimal balance = archiveStockVo.getTotalBalance().add(inventoryReportVo.getRecordBalance());
          inventoryReportVo.setBeginningBalance(balance);
          //平均成本为库存总额除以库存数量
          BigDecimal avgCost = quantity.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : balance.divide(quantity,5);
          inventoryReportVo.setBeginningAvgCost(avgCost);
        }
      });
    } else {
      param.put("endTime",beginTimeStamp);
      param.put("businessEntityId",businessEntityId);
      param.put("startRow",0);
      param.put("pageSize",Integer.MAX_VALUE);
      inventoryReportVos = MybatisTemplate.selectList("stockInventoryQRepository.inventoryReport",param);
      inventoryReportVos.forEach(inventoryReportVo -> {
        //期初库存为期初加时间段库存
        inventoryReportVo.setBeginningQuantity(inventoryReportVo.getRecordQuantity().add(inventoryReportVo.getBeginningQuantity()));
        //期初总额为时间段总格
        inventoryReportVo.setBeginningBalance(inventoryReportVo.getRecordBalance().add(inventoryReportVo.getBeginningBalance()));
        BigDecimal avgCost = inventoryReportVo.getBeginningQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : inventoryReportVo.getRecordBalance().divide(inventoryReportVo.getRecordQuantity(),5);
        inventoryReportVo.setBeginningAvgCost(avgCost);
        //其余字段清零
        inventoryReportVo.setRecordQuantity(BigDecimal.ZERO);
        inventoryReportVo.setRecordBalance(BigDecimal.ZERO);
        inventoryReportVo.setRecordAvgCost(BigDecimal.ZERO);
        inventoryReportVo.setSaleQuantity(BigDecimal.ZERO);
        inventoryReportVo.setSaleRetQuantity(BigDecimal.ZERO);
        inventoryReportVo.setPurQuantity(BigDecimal.ZERO);
        inventoryReportVo.setPurRetQuantity(BigDecimal.ZERO);
        inventoryReportVo.setOtherInQuantity(BigDecimal.ZERO);
        inventoryReportVo.setOtherOutQuantity(BigDecimal.ZERO);
        inventoryReportVo.setLossQuantity(BigDecimal.ZERO);
        inventoryReportVo.setSpillQuantity(BigDecimal.ZERO);
        inventoryReportVoMap.put(inventoryReportVo.getDepotId()+":"+inventoryReportVo.getGoodsId(),inventoryReportVo);
      });
    }
    return inventoryReportVoMap;
  }

  /**
   * 获取统计报表的结尾数据(总库存)
   * @param endTimeStamp
   * @return
   */
  private void setEndStock(String endTimeStamp,Long businessEntityId,Map<String,InventoryReportVo> beginInventoryReportVoMap) {
    Map<String, InventoryReportVo> inventoryReportVoMap = new HashMap<>();
    List<InventoryReportVo> inventoryReportVos = null;
    Map<String,Object> param = new HashMap<>();
    Wrapper wrapper = Wrapper.build().append(Restrictions.eq("businessEntityId",businessEntityId)).append(Restrictions.lt("archiveEndTimeStamp",endTimeStamp)).order(Order.desc("archiveEndTimeStamp"));
    ArchiveVo archiveVo = archiveReadRepository.getOne(wrapper);
    if (archiveVo != null) {
      List<ArchiveStockVo> archiveStockVos = (List<ArchiveStockVo>) archiveReadRepository.findStockByArchiveId(archiveVo.getId());
      param.put("beginTime",archiveVo.getArchiveEndTimeStamp());
      param.put("endTime",endTimeStamp);
      param.put("businessEntityId",businessEntityId);
      inventoryReportVos = MybatisTemplate.selectList("stockInventoryQRepository.getStockRecordByTimeFrame",param);
      inventoryReportVos.forEach(inventoryReportVo -> {
        inventoryReportVoMap.put(inventoryReportVo.getDepotId()+":"+inventoryReportVo.getGoodsId(),inventoryReportVo);
      });
      archiveStockVos.forEach(archiveStockVo -> {
        String key = archiveStockVo.getDepotId()+":"+archiveStockVo.getGoodsId();
        if (inventoryReportVoMap.get(key) != null) {
          InventoryReportVo inventoryReportVo = inventoryReportVoMap.get(key);
          //库存数量为结存总数加时间段内库存
          BigDecimal quantity = archiveStockVo.getTotalQuantity().add(inventoryReportVo.getRecordQuantity());
          inventoryReportVo.setBeginningQuantity(quantity);
          inventoryReportVo.setTotalQuantity(quantity);
          //库存总额为结存总额加时间段内总额
          BigDecimal balance = archiveStockVo.getTotalBalance().add(inventoryReportVo.getRecordBalance());
          inventoryReportVo.setBeginningBalance(balance);
          inventoryReportVo.setTotalBalance(balance);
          //平均成本为结存总额除以库存数量
          BigDecimal avgCost = quantity.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : balance.divide(quantity, 5);
          inventoryReportVo.setBeginningAvgCost(avgCost);
          inventoryReportVo.setTotalAvgCost(avgCost);
        }
      });
    } else {
      param.put("endTime",endTimeStamp);
      param.put("businessEntityId",businessEntityId);
      param.put("startRow",0);
      param.put("pageSize",Integer.MAX_VALUE);
      inventoryReportVos = MybatisTemplate.selectList("stockInventoryQRepository.inventoryReport",param);
      inventoryReportVos.forEach(inventoryReportVo -> {
        //期初库存为总库存
        inventoryReportVo.setBeginningQuantity(inventoryReportVo.getTotalQuantity());
        //期初总额为总库存总额
        inventoryReportVo.setBeginningBalance(inventoryReportVo.getTotalBalance());
        //平均成本为总库存平均成本
        inventoryReportVo.setBeginningAvgCost(inventoryReportVo.getTotalAvgCost());
        inventoryReportVoMap.put(inventoryReportVo.getDepotId()+":"+inventoryReportVo.getGoodsId(),inventoryReportVo);
      });
    }

    //拼接
    for (String key: beginInventoryReportVoMap.keySet()) {
      if (inventoryReportVoMap.get(key) != null) {
        InventoryReportVo beginInventoryReportVo = beginInventoryReportVoMap.get(key);
        InventoryReportVo endInventoryReportVo = inventoryReportVoMap.get(key);
        beginInventoryReportVo.setTotalQuantity(endInventoryReportVo.getTotalQuantity());
        beginInventoryReportVo.setTotalBalance(endInventoryReportVo.getTotalBalance());
        beginInventoryReportVo.setTotalAvgCost(endInventoryReportVo.getTotalAvgCost());

        beginInventoryReportVo.setSaleQuantity(beginInventoryReportVo.getSaleQuantity().add(endInventoryReportVo.getSaleQuantity()));
        beginInventoryReportVo.setSaleRetQuantity(beginInventoryReportVo.getSaleRetQuantity().add(endInventoryReportVo.getSaleRetQuantity()));
        beginInventoryReportVo.setPurQuantity(beginInventoryReportVo.getPurQuantity().add(endInventoryReportVo.getPurQuantity()));
        beginInventoryReportVo.setPurRetQuantity(beginInventoryReportVo.getPurRetQuantity().add(endInventoryReportVo.getPurRetQuantity()));
        beginInventoryReportVo.setOtherInQuantity(beginInventoryReportVo.getOtherInQuantity().add(endInventoryReportVo.getOtherInQuantity()));
        beginInventoryReportVo.setOtherOutQuantity(beginInventoryReportVo.getOtherOutQuantity().add(endInventoryReportVo.getOtherOutQuantity()));
        beginInventoryReportVo.setLossQuantity(beginInventoryReportVo.getLossQuantity().add(endInventoryReportVo.getLossQuantity()));
        beginInventoryReportVo.setSpillQuantity(beginInventoryReportVo.getSpillQuantity().add(endInventoryReportVo.getSpillQuantity()));
        beginInventoryReportVo.setRecordQuantity(beginInventoryReportVo.getRecordQuantity().add(endInventoryReportVo.getRecordQuantity()));
        beginInventoryReportVo.setRecordBalance(beginInventoryReportVo.getRecordBalance().add(endInventoryReportVo.getRecordBalance()));
        BigDecimal avgCost = beginInventoryReportVo.getRecordQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : beginInventoryReportVo.getRecordBalance().divide(beginInventoryReportVo.getRecordQuantity(), 5);
        beginInventoryReportVo.setRecordAvgCost(avgCost);
      }
    }
  }

  /**
   * 获取统计中间的出入库数据
   * @param beginTimeStamp 开始时间
   * @param endTimeStamp 结束时间
   * @param beginInventoryReportVoMap 期初信息
   * @return
   */
  private void setMiddleStock(String beginTimeStamp,String endTimeStamp,Map<String,InventoryReportVo> beginInventoryReportVoMap,Long businessEntityId) {
    Map<String,Object> param = new HashMap<>();
    Wrapper wrapper = Wrapper.build().append(Restrictions.gt("archiveEndTimeStamp",beginTimeStamp))
            .append(Restrictions.lt("archiveEndTimeStamp",endTimeStamp))
            .append(Restrictions.eq("businessEntityId",businessEntityId))
            .order(Order.asc("archiveEndTimeStamp"));
    List<ArchiveVo> archiveVos = archiveReadRepository.getList(wrapper);
    if (!archiveVos.isEmpty()) {
      param.put("beginTime",beginTimeStamp);
      param.put("endTime",archiveVos.get(0).getArchiveEndTimeStamp());
      param.put("businessEntityId",businessEntityId);
      param.put("startRow",0);
      param.put("pageSize",Integer.MAX_VALUE);
      List<InventoryReportVo> inventoryReportVos = MybatisTemplate.selectList("stockInventoryQRepository.inventoryReport",param);
      inventoryReportVos.forEach(inventoryReportVo -> {
        String key = inventoryReportVo.getDepotId()+":"+inventoryReportVo.getGoodsId();
        if (beginInventoryReportVoMap.get(key) != null) {
          InventoryReportVo beginInventoryReportVo = beginInventoryReportVoMap.get(key);
          beginInventoryReportVo.setSaleQuantity(beginInventoryReportVo.getSaleQuantity().add(inventoryReportVo.getSaleQuantity()));
          beginInventoryReportVo.setSaleRetQuantity(beginInventoryReportVo.getSaleRetQuantity().add(inventoryReportVo.getSaleRetQuantity()));
          beginInventoryReportVo.setPurQuantity(beginInventoryReportVo.getPurQuantity().add(inventoryReportVo.getPurQuantity()));
          beginInventoryReportVo.setPurRetQuantity(beginInventoryReportVo.getPurRetQuantity().add(inventoryReportVo.getPurRetQuantity()));
          beginInventoryReportVo.setOtherInQuantity(beginInventoryReportVo.getOtherInQuantity().add(inventoryReportVo.getOtherInQuantity()));
          beginInventoryReportVo.setOtherOutQuantity(beginInventoryReportVo.getOtherOutQuantity().add(inventoryReportVo.getOtherOutQuantity()));
          beginInventoryReportVo.setLossQuantity(beginInventoryReportVo.getLossQuantity().add(inventoryReportVo.getLossQuantity()));
          beginInventoryReportVo.setSpillQuantity(beginInventoryReportVo.getSpillQuantity().add(inventoryReportVo.getSpillQuantity()));
          beginInventoryReportVo.setRecordQuantity(beginInventoryReportVo.getRecordQuantity().add(inventoryReportVo.getRecordQuantity()));
          beginInventoryReportVo.setRecordBalance(beginInventoryReportVo.getRecordBalance().add(inventoryReportVo.getRecordBalance()));
          BigDecimal avgCost = beginInventoryReportVo.getRecordQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : beginInventoryReportVo.getRecordBalance().divide(beginInventoryReportVo.getRecordQuantity(),5);
          beginInventoryReportVo.setRecordAvgCost(avgCost);
        }
      });
    }
    if (archiveVos.size() > 1) {
      Wrapper betweenWp = Wrapper.build().append(Restrictions.gt("archiveEndTimeStamp",archiveVos.get(0).getArchiveEndTimeStamp()))
              .append(Restrictions.lt("archiveEndTimeStamp",endTimeStamp))
              .append(Restrictions.eq("businessEntityId",businessEntityId))
              .order(Order.asc("archiveEndTimeStamp"));
      List<ArchiveStockVo> archiveStockVos = (List<ArchiveStockVo>) archiveReadRepository.findStock(betweenWp);
      archiveStockVos.forEach(archiveStockVo -> {
        String key = archiveStockVo.getDepotId()+":"+archiveStockVo.getGoodsId();
        if (beginInventoryReportVoMap.get(key) != null) {
          InventoryReportVo inventoryReportVo = beginInventoryReportVoMap.get(key);
          inventoryReportVo.setSaleQuantity(inventoryReportVo.getSaleQuantity().add(archiveStockVo.getSaleQuantity()));
          inventoryReportVo.setSaleRetQuantity(inventoryReportVo.getSaleRetQuantity().add(archiveStockVo.getSaleReturnQuantity()));
          inventoryReportVo.setPurQuantity(inventoryReportVo.getPurQuantity().add(archiveStockVo.getPurchaseQuantity()));
          inventoryReportVo.setPurRetQuantity(inventoryReportVo.getPurRetQuantity().add(archiveStockVo.getPurchaseReturnQuantity()));
          inventoryReportVo.setOtherInQuantity(inventoryReportVo.getOtherInQuantity().add(archiveStockVo.getOtherInQuantity()));
          inventoryReportVo.setOtherOutQuantity(inventoryReportVo.getOtherOutQuantity().add(archiveStockVo.getOtherOutQuantity()));
          inventoryReportVo.setLossQuantity(inventoryReportVo.getLossQuantity().add(archiveStockVo.getLossQuantity()));
          inventoryReportVo.setSpillQuantity(inventoryReportVo.getSpillQuantity().add(archiveStockVo.getSpillQuantity()));
          inventoryReportVo.setRecordQuantity(inventoryReportVo.getRecordQuantity().add(archiveStockVo.getRecordQuantity()));
          inventoryReportVo.setRecordBalance(inventoryReportVo.getRecordBalance().add(archiveStockVo.getRecordBalance()));
          BigDecimal avgCost = inventoryReportVo.getRecordQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : inventoryReportVo.getRecordBalance().divide(inventoryReportVo.getRecordQuantity(),BigDecimal.ROUND_HALF_UP);
          inventoryReportVo.setRecordAvgCost(avgCost);
        }
      });
    }
  }

}
